package com.project.book.order.distributed.security.order.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableResourceServer
// 或者是单独配置WebSecurityConfig也可以
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    /**
     * 资源列表，与服务端的resourceIds一致
     */
    private static final String RESOURCE_ID = "res1";

    /**
     * 从TokenConfig中注入tokenStore
     */
    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        // 资源id
        resources.resourceId(RESOURCE_ID)
                // 验证令牌的服务
                .tokenServices(tokenService())
                .stateless(true);
    }

    /**
     * 资源访问策略
     * 注意:1.这些规则会按照给定的顺序发挥作用。所以，很重要的一点就是将最为具体的请求路径放在前面，
     * 而最不具体的路径（如anyRequest()）放在最后面。如果不这样做的话，那不具体的路径配置将会覆盖掉更为具体的路径配置。
     *     2.因为是按照顺序的，所以上面的通过了，就不会验证下面的了
     * @param http
     * @throws Exception
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/r1").hasAnyAuthority("p1")//比如这个具体的url要比下面的/**放前面
                .antMatchers("/r2").hasAnyAuthority("p2")
                .antMatchers("/**").access("#oauth2.hasScope('all')") // 所有的请求都必须有scope=all，跟服务端一致
                .anyRequest().permitAll() // 除了/r/**，其他的请求都可以访问
                .and().csrf().disable() // 关闭CSRF
                // 基于token的方式，session就不用再记录了
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }


    /**
     * 资源服务令牌解析服务
     * @return
     */
    @Bean
    public ResourceServerTokenServices tokenService() {
        // 使用远程服务请求授权服务校验token，必须制定校验token的URL、client_id、client_secret
        RemoteTokenServices service = new RemoteTokenServices();
        service.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
        service.setClientId("c1");
        service.setClientSecret("secret");
        return service;
    }

}